package org.ehe.finance.receipt.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.ehe.common.core.exception.ServiceException;
import org.ehe.common.core.utils.DateUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.finance.receipt.domain.ErpFinanceReceipt;
import org.ehe.finance.receipt.domain.ErpFinanceReceiptDetail;
import org.ehe.finance.receipt.domain.bo.ReceiptBo;
import org.ehe.finance.receipt.domain.bo.ReceiptDetailBo;
import org.ehe.finance.receipt.domain.vo.ReceiptResponseVO;
import org.ehe.finance.receipt.mapper.ReceiptDetailMapper;
import org.ehe.finance.receipt.mapper.ReceiptMapper;
import org.ehe.finance.receipt.service.ReceiptService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 收款单ServiceImpl
 * @author :zhangnn
 * @className :ReceiptServiceImpl
 * @description: TODO
 * @date 2025-09-02 14:29:19
 */
@Service
@RequiredArgsConstructor
public class ReceiptServiceImpl extends ServiceImpl<ReceiptMapper, ErpFinanceReceipt> implements ReceiptService {

    private final ReceiptMapper receiptMapper;
    private final ReceiptDetailMapper receiptDetailMapper;

    /**
     * 分页
     * @param queryVO 查询条件
     * @param pageQuery 分页参数
     * @return
     */
    @Override
    public TableDataInfo<ReceiptResponseVO> selectReceiptPage(ReceiptBo queryVO, PageQuery pageQuery) {
        Page<ReceiptResponseVO> page = pageQuery.build();
        Page<ReceiptResponseVO> result = receiptMapper.selectReceiptPage(page, queryVO);
        return TableDataInfo.build(result);
    }

    /**
     * 查询收款单详情
     * @param id 收款单ID
     * @return 收款单详情
     */
    @Override
    public ErpFinanceReceipt getReceiptDetail(Long id) {
        ErpFinanceReceipt receipt = receiptMapper.selectById(id);
        if (receipt != null) {
            List<ErpFinanceReceiptDetail> details = receiptDetailMapper.selectDetailByReceiptId(id);
            receipt.setReceiptDetails(details);
        }
        return receipt;
    }
    /**
     * 创建收款单
     * @param receiptBo 收款单业务对象
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createReceipt(ReceiptBo receiptBo) {
        // 1. 参数验证
        validateReceiptBo(receiptBo);

        // 2. 检查收款单号是否存在
        if (checkReceiptNoExists(receiptBo.getReceiptNo(), null)) {
            throw new ServiceException("收款单号已存在：" + receiptBo.getReceiptNo());
        }

        // 3. 验证收款明细金额合计
        BigDecimal detailTotalAmount = receiptBo.getReceiptDetails().stream()
            .map(detail -> detail.getSettleAmount().add(detail.getDiscountAmount()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (receiptBo.getTotalAmount().compareTo(detailTotalAmount) != 0) {
            throw new ServiceException("收款总金额与明细金额合计不一致");
        }

        // 4. 创建收款单主表
        ErpFinanceReceipt receipt = BeanUtil.copyProperties(receiptBo, ErpFinanceReceipt.class);
        receipt.setStatus(1); // 默认未审核状态

        boolean mainResult = save(receipt);
        if (!mainResult) {
            throw new ServiceException("创建收款单失败");
        }

        // 5. 创建收款明细
        if (receiptBo.getReceiptDetails() != null && !receiptBo.getReceiptDetails().isEmpty()) {
            List<ErpFinanceReceiptDetail> details = convertToDetailEntities(receiptBo.getReceiptDetails(), receipt.getId());
            int detailResult = receiptDetailMapper.batchInsertDetails(details);
            if (detailResult != details.size()) {
                throw new ServiceException("创建收款明细失败");
            }
        }

        return true;
    }

    /**
     * 更新收款单
     * @param receiptBo 收款单业务对象
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateReceipt(ReceiptBo receiptBo) {
        // 1. 参数验证
        validateReceiptBo(receiptBo);

        // 2. 检查收款单是否存在
        ErpFinanceReceipt existingReceipt = getById(receiptBo.getId());
        if (existingReceipt == null) {
            throw new ServiceException("收款单不存在，ID：" + receiptBo.getId());
        }

        // 3. 检查是否已审核
        if (existingReceipt.getStatus().equals(2)) {
            throw new ServiceException("已审核的收款单不能修改");
        }

        // 4. 检查收款单号是否存在
        if (checkReceiptNoExists(receiptBo.getReceiptNo(), receiptBo.getId())) {
            throw new ServiceException("收款单号已存在：" + receiptBo.getReceiptNo());
        }

        // 5. 验证收款明细金额合计
        BigDecimal detailTotalAmount = receiptBo.getReceiptDetails().stream()
            .map(detail -> detail.getSettleAmount().add(detail.getDiscountAmount()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (receiptBo.getTotalAmount().compareTo(detailTotalAmount) != 0) {
            throw new ServiceException("收款总金额与明细金额合计不一致");
        }

        // 6. 更新收款单主表
        ErpFinanceReceipt receipt = BeanUtil.copyProperties(receiptBo, ErpFinanceReceipt.class);
        boolean mainResult = updateById(receipt);
        if (!mainResult) {
            throw new ServiceException("更新收款单失败");
        }

        // 7. 删除原有明细
        receiptDetailMapper.deleteByReceiptId(receiptBo.getId());

        // 8. 创建新明细
        if (receiptBo.getReceiptDetails() != null && !receiptBo.getReceiptDetails().isEmpty()) {
            List<ErpFinanceReceiptDetail> details = convertToDetailEntities(receiptBo.getReceiptDetails(), receipt.getId());
            int detailResult = receiptDetailMapper.batchInsertDetails(details);
            if (detailResult != details.size()) {
                throw new ServiceException("更新收款明细失败");
            }
        }

        return true;
    }
    /**
     * 删除收款单
     * @param id 收款单ID
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteReceipt(Long id) {
        if (id == null || id <= 0) {
            throw new ServiceException("收款单ID不能为空");
        }

        ErpFinanceReceipt receipt = getById(id);
        if (receipt == null) {
            throw new ServiceException("收款单不存在，ID：" + id);
        }

        // 检查是否已审核
        if (receipt.getStatus().equals(2)) {
            throw new ServiceException("已审核的收款单不能删除");
        }

        // 删除明细
        receiptDetailMapper.deleteByReceiptId(id);

        // 删除主表
        return removeById(id);
    }

    /**
     * 批量删除收款单
     * @param idList 收款单ID列表
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDeleteReceipt(List<Long> idList) {
        if (idList == null || idList.isEmpty()) {
            throw new ServiceException("删除的收款单ID列表不能为空");
        }

        // 检查是否有已审核的收款单
        List<ErpFinanceReceipt> receipts = listByIds(idList);
        if (receipts.isEmpty()) {
            throw new ServiceException("没有找到要删除的收款单");
        }

        List<String> auditedReceiptNos = receipts.stream()
            .filter(receipt -> receipt.getStatus().equals(2))
            .map(ErpFinanceReceipt::getReceiptNo)
            .collect(Collectors.toList());

        if (!auditedReceiptNos.isEmpty()) {
            throw new ServiceException("以下收款单已审核，无法删除：" + String.join("、", auditedReceiptNos));
        }

        // 删除明细
        receiptDetailMapper.batchDeleteByReceiptIds(idList);

        // 删除主表
        return removeBatchByIds(idList);
    }
    /**
     * 更新收款金额
     * @param id 收款单ID
     * @param amount 收款金额
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateReceiptAmount(Long id, BigDecimal amount) {
        if (id == null || id <= 0) {
            throw new ServiceException("收款单ID不能为空");
        }
        if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("收款金额必须大于0");
        }

        ErpFinanceReceipt receipt = getById(id);
        if (receipt == null) {
            throw new ServiceException("收款单不存在，ID：" + id);
        }

        // 检查是否已审核
        if (receipt.getStatus().equals(2)) {
            throw new ServiceException("已审核的收款单不能修改金额");
        }

        receipt.setTotalAmount(amount);
        return updateById(receipt);
    }
    /**
     * 查询即将到期收款
     * @param days 天数
     * @return 即将到期收款列表
     */
    @Override
    public List<ErpFinanceReceipt> getDueReceipts(int days) {
        return receiptMapper.selectDueReceipts(days);
    }
    /**
     * 客户收款统计
     * @return 统计结果
     */
    @Override
    public List<ReceiptMapper.ReceiptStatistics> getReceiptStatisticsByCustomer() {
        return receiptMapper.selectReceiptStatisticsByCustomer();
    }
    /**
     * 生成收款单号
     * @return 收款单号
     */
    @Override
    public String generateReceiptNo() {
        String prefix = "SK";
        String datePart = DateUtils.getCurrentDate();//DateUtil.format(LocalDate.now(), "yyyyMMdd");

        // 查询当天最大流水号
        String pattern = prefix + datePart + "%";
        LambdaQueryWrapper<ErpFinanceReceipt> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(ErpFinanceReceipt::getReceiptNo, pattern)
            .orderByDesc(ErpFinanceReceipt::getReceiptNo)
            .last("LIMIT 1");

        ErpFinanceReceipt lastReceipt = getOne(wrapper);

        int sequence = 1;
        if (lastReceipt != null && lastReceipt.getReceiptNo().startsWith(prefix + datePart)) {
            String lastSequence = lastReceipt.getReceiptNo().substring((prefix + datePart).length());
            try {
                sequence = Integer.parseInt(lastSequence) + 1;
            } catch (NumberFormatException e) {
                // 如果解析失败，从1开始
                sequence = 1;
            }
        }

        return prefix + datePart + String.format("%04d", sequence);
    }
    /**
     * 审核收款单
     * @param id 收款单ID
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditReceipt(Long id) {
        if (id == null || id <= 0) {
            throw new ServiceException("收款单ID不能为空");
        }

        ErpFinanceReceipt receipt = getById(id);
        if (receipt == null) {
            throw new ServiceException("收款单不存在，ID：" + id);
        }

        if (receipt.getStatus().equals(2)) {
            throw new ServiceException("收款单已审核，无需重复审核");
        }

        // 验证收款单完整性
        validateReceiptForAudit(receipt);

        receipt.setStatus(2);
        return updateById(receipt);
    }

    /**
     * 反审核收款单
     * @param id 收款单ID
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unauditReceipt(Long id) {
        if (id == null || id <= 0) {
            throw new ServiceException("收款单ID不能为空");
        }

        ErpFinanceReceipt receipt = getById(id);
        if (receipt == null) {
            throw new ServiceException("收款单不存在，ID：" + id);
        }

        if (receipt.getStatus().equals(1)) {
            throw new ServiceException("收款单未审核，无需反审核");
        }

        receipt.setStatus(1);
        return updateById(receipt);
    }

    /**
     * 检查收款单号是否存在
     * @param receiptNo 收款单号
     * @param id 排除的ID
     * @return 是否存在
     */
    @Override
    public boolean checkReceiptNoExists(String receiptNo, Long id) {
        if (receiptNo == null || receiptNo.trim().isEmpty()) {
            return false;
        }
        return receiptMapper.checkReceiptNoExists(receiptNo.trim(), id) > 0;
    }

    /**
     * 验证收款单业务对象
     */
    private void validateReceiptBo(ReceiptBo receiptBo) {
        if (receiptBo == null) {
            throw new ServiceException("收款单数据不能为空");
        }

        // 验证收款日期不能超过当前日期
        if (receiptBo.getReceiptDate() != null && receiptBo.getReceiptDate().isAfter(LocalDate.now())) {
            throw new ServiceException("收款日期不能超过当前日期");
        }

        // 验证明细不能为空
        if (receiptBo.getReceiptDetails() == null || receiptBo.getReceiptDetails().isEmpty()) {
            throw new ServiceException("收款明细不能为空");
        }

        // 验证明细金额
        for (ReceiptDetailBo detail : receiptBo.getReceiptDetails()) {
            if (detail.getSettleAmount() == null || detail.getSettleAmount().compareTo(BigDecimal.ZERO) <= 0) {
                throw new ServiceException("收款明细核销金额必须大于0");
            }
        }
    }

    /**
     * 验证收款单是否可以审核
     */
    private void validateReceiptForAudit(ErpFinanceReceipt receipt) {
        // 验证收款金额
        if (receipt.getTotalAmount() == null || receipt.getTotalAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("收款金额必须大于0，无法审核");
        }

        // 验证是否有明细
        List<ErpFinanceReceiptDetail> details = receiptDetailMapper.selectDetailByReceiptId(receipt.getId());
        if (details.isEmpty()) {
            throw new ServiceException("收款单没有明细，无法审核");
        }

        // 验证明细金额合计
        BigDecimal detailTotal = details.stream()
            .map(detail -> detail.getSettleAmount().add(detail.getDiscountAmount()))
            .reduce(BigDecimal.ZERO, BigDecimal::add);

        if (receipt.getTotalAmount().compareTo(detailTotal) != 0) {
            throw new ServiceException("收款单总金额与明细金额合计不一致，无法审核");
        }
    }

    /**
     * 转换收款明细BO为实体
     */
    private List<ErpFinanceReceiptDetail> convertToDetailEntities(List<ReceiptDetailBo> detailBos, Long receiptId) {
        return detailBos.stream().map(detailBo -> {
            ErpFinanceReceiptDetail detail = new ErpFinanceReceiptDetail();
            detail.setReceiptId(receiptId);
            detail.setReceivableId(detailBo.getReceivableId());
            detail.setSettleAmount(detailBo.getSettleAmount());
            detail.setDiscountAmount(detailBo.getDiscountAmount());
            detail.setRemark(detailBo.getRemark());
            return detail;
        }).collect(Collectors.toList());
    }
}
